/*
 * Created on Wed Jun 06 2018 by Ronnie Ren (zhaosong.ren) from Accenture
 *
 * Copyright (c) 2018 DingXing information & technology limited company.
 */

import { Injectable } from "@angular/core";
import { SqliteService } from "../../services/sqliteDB/sqlite.service";
import { BillDto } from "../dto/bill.dto";
import { Bill } from "../transform/bill";
import { Observable } from "rxjs/Observable";
import { JsonMappingUtil } from "../json-mapping-util";
import { ElectricityMeter } from "../transform/electricity-meter";
import { ElectricityMeterDto } from "../dto/electricity-meter.dto";
import { AttachmentService } from "./attachment.service";
import { CurdService } from "./curd.service";
import { SyncStatus } from "../sync-status";
import {Attachment} from "../transform/attachment";



@Injectable()
export class BillService {

  constructor(
    private sqliteService: SqliteService,
    private attachmentService: AttachmentService,
    private curdService: CurdService,
  ) {

  }

  fetchBillsByUserId(userId: string): Observable<Array<Bill>> {
    let billDto = new BillDto();
    return Observable.fromPromise(
      this.sqliteService.executeSqlWithResults<BillDto>(`select * from ${billDto.table().tableName} where userId = '${userId}'`, BillDto)
    )
      .map((dtos: Array<BillDto>) => dtos.map((dto) => new Bill(dto)))
      .flatMap((bills) => {
        return this.fetchElectricity(bills).map(() => bills);
      });
  }

  fetchBillByUserIdAndMonth(userId: string, billMonth: string): Observable<Bill> {
    let billDto = new BillDto();
    return Observable.fromPromise(
      this.sqliteService.executeSqlWithResults<BillDto>(`select * from ${billDto.table().tableName} ` +
        `where userId = '${userId}' AND month = ${billMonth}`, BillDto)
    )
      .map((dtos: Array<BillDto>) => {
        if (dtos.length > 0) {
          return new Bill(dtos[0]);
        }
        return null;
      })
      .flatMap((bills) => {
        return Observable.of(bills);
      });
  }

  submitData(paths: Array<Attachment>, data: any, bill: Bill) {
    if (paths.length > 0) {
      let pathArray: Array<string> = [];
      paths.forEach((item) => {
        pathArray.push(item.path);
      });
      let attachments = bill.addNoticeAttachments(pathArray);
      this.attachmentService.addImg(attachments);
      bill.attachmentIds = attachments.map((item) => item.id).join(",");
      console.log('imageId' + bill.attachmentIds);
    }

    console.log(data);
    bill.noticeUploadTime = data.noticeTime;
    let billDto = new BillDto();
    billDto.noticeUploadTime = bill.noticeUploadTime;
    billDto.attachmentIds = bill.attachmentIds;

    // JsonMappingUtil.MappingAllProp

    return Observable.fromPromise(this.curdService.update(
      { dto: BillDto, mapObj: Bill }, { noticeUploadTime: bill.noticeUploadTime, attachmentId: bill.attachmentIds },
      { and: { userId: bill.userId, month: bill.month } }));
  }

  fetchBillsBySyncStatus(syncStatuses: Array<SyncStatus>, count: number = 1): Observable<Array<Bill>> {
    return this.curdService.observableFetchObjectsByPage(
      BillDto,
      null,
      [{ syncStatus: syncStatuses }]
    )
      .flatMap((billDtos: Array<BillDto>) => {
        //
        // TODO write a recursive method to split the objects to multi-piece
        // and then combine them togather.
        // now I just split them into 10 items per page.
        //
        // let billPages = billDtos.chunk(10);
        // get unSync BillDto
        if (!billDtos || billDtos.length < 1 ) {
          return Observable.of([]);
        } else {
          return Observable.combineLatest(
            billDtos.map((billDto) => this.getBillsAndAttachmentsFromBillDtos(billDto))
          )
            .map((billsArray) => billsArray.reduce((result, bills) => result.concat(bills), []));
        }
      });
  }

  private getBillsAndAttachmentsFromBillDtos(billDto: BillDto): Observable<Bill> {
    // let obs = billDtos.map((dto) => {
      let bill = new Bill({});
      JsonMappingUtil.MappingAllProp(billDto, bill);
      if (!bill.attachmentIds) {
        bill.attachmentIds = '';
      }
      return this.attachmentService.fetchAttachmentByIds(bill.attachmentIds.split(","))
        .do((attachments) => {
          bill.noticeAttachments = attachments;
        })
        .map(() => {
          console.log(bill);
          return bill;
        });
  }

  private fetchElectricity(bills: Array<Bill>): Observable<Array<ElectricityMeter>> {
    return Observable.create((subscriber) => {
      let totalCount = bills.length;
      let fetchedCount = 0;
      let allElectricity: Array<ElectricityMeter> = [];
      for (let bill of bills) {
        let orConditions = [{ userId: bill.userId }, { billDate: bill.billDate }];
        Observable.fromPromise(this.sqliteService.fetch(ElectricityMeterDto, { or: orConditions }))
          .subscribe((electricity: Array<ElectricityMeter>) => {
            bill.consumedElectricitys = electricity;
            fetchedCount += 1;
            allElectricity = allElectricity.concat(electricity);
            if (fetchedCount === totalCount) {
              subscriber.next(allElectricity);
              subscriber.complete();
            }
          });
      }

    });
  }












}
